#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const int N = 1e5, M = N * 2;
int h[N], e[M], ne[M], w[M], idx;
int sz[N], fa[N], top[N], dep[N], son[N], id[N], nw[N];
int cnt, a[N];
int n, m;
struct node
{
	int l, r;
	LL add, sum;
}tree[N * 4];
void add(int a, int b)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs1(int u, int father)
{
	fa[u] = father;
	sz[u] = 1;
	dep[u] = dep[father] + 1;
	for (int i = h[u]; ~i; i = ne[i]) {
		int j = e[i];
		if (j == father)continue;
		dfs1(j, u);
		sz[u] += sz[j];
		if (sz[son[u]] < sz[j])son[u] = j;
	}
}

void dfs2(int u, int t)
{
	top[u] = t;
	id[u] = ++cnt;
	nw[cnt] = w[u];
	if (!son[u])return;
	dfs2(son[u], t);
	for (int i = h[u]; ~i; i = ne[i]) {
		int j = e[i];
		if (j == fa[u] || j == son[u]) continue;
		dfs2(j, j);
	}
}


void pushup(int u)
{
	tree[u].sum = tree[u << 1].sum + tree[u << 1 | 1].sum;
}

void pushdown(int u)
{
	auto& root = tree[u], & left = tree[u << 1], & right = tree[u << 1 | 1];
	if (root.add) {
		left.add += root.add;
		left.sum += (root.add) * (left.r - left.l + 1);
		right.add += root.add;
		right.sum += (root.add) * (right.r - right.l + 1);
		root.add = 0;
	}
}
void build(int u, int l, int r)
{
	tree[u] = { l,r,0,w[l] };
	if (l == r)return;
	int mid = l + r >> 1;
	build(u << 1, l, mid);
	build(u << 1 | 1, mid + 1, r);
	pushup(u);
}

void modify(int u, int l, int r, int x)
{
	if (tree[u].l >= l && tree[u].r <= r) {
		tree[u].add += x;
		tree[u].sum += x * (tree[u].r - tree[u].l + 1);
		return;
	}
	pushdown(u);
	int mid = tree[u].l + tree[u].r >> 1;
	if (l <= mid)modify(u << 1, l, r, x);
	if (mid < r) modify(u << 1 | 1, l, r, x);
	pushup(u);
}

LL query(int u, int l, int r)
{
	if (tree[u].l >= l && tree[u].r <= r) {
		return tree[u].sum;
	}
	LL res = 0;
	pushdown(u);
	int mid = tree[u].l + tree[u].r >> 1;
	if (l <= mid)res += query(u << 1, l, r);
	if (mid < r) res += query(u << 1 | 1, l, r);
	return res;
}

void modify_path(int u, int v, int x)
{
	while (top[u] != top[v]) {
		if (dep[top[u]] < dep[top[v]]) swap(u, v);
		modify(1, id[top[u]], id[u], x);
		u = fa[top[u]];
	}
	if (dep[u] < dep[v])swap(u, v);
	modify(1, id[v], id[u], x);
}

void modify_tree(int u, int x)
{
	modify(1, id[u], id[u] + sz[u] - 1, x);
}

LL query_path(int u, int v)
{
	LL res = 0;
	while (top[u] != top[v]) {
		if (dep[top[u]] < dep[top[v]]) swap(u, v);
		res += query(1, id[top[u]], id[u]);
		u = fa[top[u]];
	}
	if (dep[u] < dep[v])swap(u, v);
	res += query(1, id[v], id[u]);
	return res;
}

LL query_tree(int u)
{
	return query(1, id[u], id[u] + sz[u] - 1);
}
int main()
{
	memset(h, -1, sizeof(h));
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	for (int i = 0; i < n - 1; i++) {
		int a, b;
		cin >> a >> b;
		add(a, b);
		add(b, a);
	}
	cin >> m;
	dfs1(1, 0);
	dfs2(1, 1);
	build(1, 1, n);
	//cout<<"==="<<endl;
	while (m--) {
		int t;
		int u, v, k;
		cin >> t;
		if (t == 1) {
			cin >> u >> v >> k;
			modify_path(u, v, k);
		}
		else if (t == 2) {
			cin >> u >> k;
			modify_tree(u, k);
		}
		else if (t == 3) {
			cin >> u >> k;
			LL ans = query_path(u, k);
			cout << ans << endl;
		}
		else {
			cin >> u;
			LL ans = query_tree(u);
			cout << ans << endl;
		}
	}
	return 0;
}

